<template>
  <div>
    <!-- 弹框表单 -->
    <el-dialog
      v-dialog-drag
      :title="title"
      :modal="false"
      :appendToBody="false"
      :visible.sync="formDialogVisible"
      :close-on-click-modal="false"
      :width="width"
      top="7vh"
      @open="handleDialogOpen"
    >
      <el-form
        :model="formData"
        :rules="rules"
        ref="ruleForm"
        :label-width="getLabelWidth"
        class="demo-ruleForm"
      >
        <template v-for="item in items">
          <el-form-item
            class="form-item-col"
            :style="{float:'left', width:item.width||getStyle.width}"
            :key="item.prop"
            :label="item.label"
            :prop="item.prop"
            :rules="item.rules"
            v-if="!item.hidden"
          >
            <el-input
              v-if="item.type==='input'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(formData, {items, item}, $event)"
              @input="handleInput(formData, {items, item}, $event)"
            ></el-input>
            <el-input
              v-else-if="item.type==='number'"
              v-model.number="formData[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(formData, {items, item}, $event)"
              @input="handleInput(formData, {items, item}, $event)"
            ></el-input>
            <el-select
              v-else-if="item.type==='select'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              placeholder="请选择"
              @change="handleChange(formData, {items, item}, $event)"
            >
              <el-option
                v-for="opt in item.options"
                :key="opt.value"
                :label="opt.label"
                :value="opt.value"
              >
              </el-option>
            </el-select>
            <el-date-picker
              v-else-if="item.type==='date'"
              v-model="formData[item.prop]"
              type="date"
              :disabled="item.disabled"
              placeholder="选择日期"
              format="yyyy-MM-dd"
              value-format="yyyy-MM-dd HH:mm:ss"
              @change="handleChange(formData, {items, item}, $event)"
            >
            </el-date-picker>
            <el-date-picker
              v-else-if="item.type==='datetime'"
              v-model="formData[item.prop]"
              type="datetime"
              :disabled="item.disabled"
              placeholder="选择日期时间"
              format="yyyy-MM-dd HH:mm:ss"
              value-format="yyyy-MM-dd HH:mm:ss"
              @change="handleChange(formData, {items, item}, $event)"
            >
            </el-date-picker>
            <el-input
              v-else-if="item.type==='treeSelect'"
              v-model="treeSelectLabel[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(formData, {items, item}, $event)"
              @input="handleInput(formData, {items, item}, $event)"
            >
              <el-button
                slot="append"
                icon="el-icon-search"
                :disabled="item.disabled"
                @click="handleOpenTreeDialog(item)"
              ></el-button>
            </el-input>
            <el-input
              v-else-if="item.type==='tableSelect'"
              :value="tableSelectLabel[item.prop]"
              :disabled="item.disabled"
              clearable
              @clear="handleTableSelectClear(item.prop)"
              @change="handleChange(formData, {items, item}, $event)"
              @input="handleInput(formData, {items, item}, $event)"
            >
              <el-button
                slot="append"
                icon="el-icon-search"
                :disabled="item.disabled"
                @click="handleOpenTableDialog(formData, {items, item})"
              ></el-button>
            </el-input>
            <el-radio-group
              v-else-if="item.type==='radio-group'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(formData, {items, item}, $event)"
            >
              <el-radio
                v-for="o in item.options"
                :key="o.value"
                :label="o.value"
              >{{o.label}}</el-radio>
            </el-radio-group>
            <el-input
              v-else-if="item.type==='textarea'"
              type="textarea"
              :disabled="item.disabled"
              :rows="3"
              placeholder="请输入内容"
              v-model="formData[item.prop]"
              @change="handleChange(formData, {items, item}, $event)"
              @input="handleInput(formData, {items, item}, $event)"
            >
            </el-input>
            <el-upload
              v-else-if="item.type==='image-upload'&&!item.disabled"
              action=""
              list-type="picture-card"
              accept=".jpg,.png"
              :multiple="true"
              :auto-upload="false"
              :file-list="formData[item.prop]"
              :on-preview="handlePictureCardPreview"
              :on-change="(file,fileList)=>handlePictureCardChange(item.prop, file,fileList)"
            >
              <i class="el-icon-plus"></i>
              <div
                slot="tip"
                class="el-upload__tip"
              >只能上传.jpg, .png文件</div>
            </el-upload>
            <template v-else-if="item.type==='image-upload'&&item.disabled">
              <div
                v-for="ele in formData[item.prop]"
                :key="ele.id"
                class="picture-card-disabled-content"
              >
                <div class="picture-card-disabled-image">
                  <img
                    :src="ele.url"
                    :alt="ele.fileName"
                  />
                  <div class="zoom-modal">
                    <i
                      class="el-icon-zoom-in zoom-icon"
                      @click="handlePictureCardPreview(ele)"
                    ></i>
                  </div>
                </div>
                <div>{{ele.fileName}}</div>
              </div>
            </template>
            <el-input
              v-else-if="item.type==='organization'"
              :value="organizationLabel"
              :disabled="item.disabled"
              @change="handleChange(formData, {items, item}, $event)"
              @input="handleInput(formData, {items, item}, $event)"
            >
              <el-button
                slot="append"
                icon="el-icon-search"
                :disabled="item.disabled"
                @click="handleOpenOrganizationDialog(item)"
              ></el-button>
            </el-input>
            <el-input
              v-else-if="item.type==='userlist'"
              :value="userlistLabel[item.prop]"
              :disabled="item.disabled"
              clearable
              @clear="handleTableSelectClear(item.prop)"
              @change="handleChange(formData, {items, item}, $event)"
              @input="handleInput(formData, {items, item}, $event)"
            >
              <el-button
                slot="append"
                icon="el-icon-search"
                :disabled="item.disabled"
                @click="handleOpenUserlistDialog(item)"
              ></el-button>
            </el-input>
            <template v-else-if="item.type==='custom'">
              <!-- <slot :formData="formData" :attrs="item.attrs"></slot> -->
              <component
                ref="customComponent"
                :is="item.component"
                :attrs="item.attrs"
                :formData="formData"
                @change="handleComponentChange(item.prop, item, $event)"
              ></component>
            </template>
            <span
              v-else-if="item.type==='text'"
              class="form-text-item"
            >{{formData[item.prop]}}</span>
          </el-form-item>
        </template>
      </el-form>
      <span
        slot="footer"
        class="dialog-footer"
        v-show="hasSubmitBtn || hasCancelBtn"
      >
        <el-button
          v-if="hasSubmitBtn"
          type="primary"
          :loading="submitting"
          @click="handleFinishForm"
        >确定</el-button>
        <el-button
          v-if="hasCancelBtn"
          @click="formDialogVisible = false"
        >取 消</el-button>
      </span>
    </el-dialog>
    <!-- 上传的附件照片预览 -->
    <el-dialog
      :visible.sync="imageFileDialog.visible"
      custom-class="view-image-dialog"
      width="85%"
    >
      <img
        class="view-image"
        :src="imageFileDialog.imageUrl"
        alt=""
      >
    </el-dialog>
    <!-- 树结构 -->
    <el-dialog
      v-dialog-drag
      width="30%"
      :title="treeSelectDialog.item.label"
      :visible.sync="treeSelectDialog.visible"
      :modal="false"
      :appendToBody="false"
      top="7vh"
      height="calc(100% - 47px)"
      custom-class="select-dialog"
    >
      <el-input
        placeholder="输入关键字进行过滤"
        v-model="treeSelectDialog.keyword"
        @input="filterTree"
      >
      </el-input>
      <el-tree
        ref="selectTree"
        check-strictly
        :data="treeSelectDialog.treeData"
        show-checkbox
        node-key="id"
        :props="treeSelectDialog.defaultProps"
        :filter-node-method="filterNode"
      >
      </el-tree>
      <span
        slot="footer"
        class="dialog-footer"
      >
        <el-button
          type="primary"
          @click="handleFinishTreeSelect"
        >确 定</el-button>
        <el-button @click="treeSelectDialog.visible = false">取 消</el-button>
      </span>
    </el-dialog>
    <!-- 表格结构 -->
    <el-dialog
      v-dialog-drag
      width="65%"
      :title="tableSelectDialog.item.label"
      :visible.sync="tableSelectDialog.visible"
      :modal="false"
      :appendToBody="false"
      top="7vh"
      height="calc(100% - 47px)"
      custom-class="select-dialog"
    >
      <div class="tool-search">
        <el-input
          placeholder="输入关键字进行过滤"
          v-model="tableSelectDialog.keyword"
          clearable
          @keyup.enter.native="handleTableSearch"
        >
        </el-input>
        <el-button
          type="primary"
          size="small"
          icon="el-icon-search"
          @click="handleTableSearch"
        >查询</el-button>
      </div>
      <div class="tool-table">
        <el-table
          ref="Table"
          :data="tableSelectDialog.tableData"
          stripe
          border
          tooltip-effect="dark"
          style="width: 100%"
          :height="tableSelectDialog.pager.total>0?'calc(100% - 50px - 15px)':'calc(100% - 15px)'"
          @select="handleTableSelect"
          @row-click="handleRowClick"
        >
          <el-table-column
            type="selection"
            width="55"
          >
          </el-table-column>
          <el-table-column
            v-for="col in tableSelectDialog.columns"
            :key="col.prop"
            :prop="col.prop"
            :label="col.label"
            show-overflow-tooltip
            :min-width="col.minWidth"
          >
          </el-table-column>
        </el-table>
        <div class="pagination">
          <pagination
            v-show="tableSelectDialog.pager.total>0"
            :total="tableSelectDialog.pager.total"
            :page.sync="tableSelectDialog.pager.pageNum"
            :limit.sync="tableSelectDialog.pager.pageSize"
            @pagination="handlePageChange"
          />
        </div>
      </div>
      <span
        slot="footer"
        class="dialog-footer"
      >
        <el-button
          type="primary"
          @click="handleFinishTableSelect"
        >确 定</el-button>
        <el-button @click="tableSelectDialog.visible = false">取 消</el-button>
      </span>
    </el-dialog>
    <!-- 组织机构 -->
    <organization
      :branchcode="branchcode"
      :visibles="organizationDialog.visible"
      @closeDialog="closeOrganization"
    ></organization>
    <!-- 人员列表 -->
    <userList2
      :visibles="userListDialog.visible"
      :isRadio="!!userListDialog.item.isRadio"
      @closeDialog="closeUserList"
    ></userList2>
  </div>
</template>
<script>
import combination from '@/components/FormDialog/combination'
export default {
  components: { combination },
  props: {
    // 弹框显示隐藏
    visible: {
      type: Boolean,
      default: false
    },
    // 弹框标题
    title: {
      type: String,
      default: '弹框'
    },
    // 弹框宽度
    width: {
      type: String,
      default: '70%'
    },
    // 表单项配置
    defaultItems: {
      type: Array,
      default: () => []
    },
    // 展示的表单项的列数
    columnNum: {
      type: Number,
      default: 1
    },
    // 是否在打开弹框时先初始化各表单项的联动关系，一般为执行配置的change方法
    isInit: {
      type: Boolean,
      default: false
    },
    // 表单label宽度
    labelWidth: {
      type: String,
      default: '130px'
    },
    // 提交后自动关闭弹框
    autoCloseAfterSubmit: {
      type: Boolean,
      default: true
    },
    // 是否有提交确定按钮
    hasSubmitBtn: {
      type: Boolean,
      default: true
    },
    // 是否有取消按钮
    hasCancelBtn: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      items: [],
      formData: {},
      rules: {},
      treeSelectDialog: {
        item: {},
        visible: false,
        defaultProps: {
          children: 'children',
          label: 'name'
        },
        keyword: '',
        treeData: []
      },
      imageFileDialog: {
        visible: false,
        imageUrl: ''
      },
      tableSelectDialog: {
        item: {},
        visible: false,
        keyword: '',
        columns: [],
        tableData: [],
        pager: {
          total: 0,
          pageNum: 1,
          pageSize: 10
        }
      },
      organizationDialog: {
        item: {},
        visible: false
      },
      userListDialog: {
        item: {},
        visible: false
      },
      branchcode: '',
      submitting: false
    }
  },
  computed: {
    formDialogVisible: {
      set(val) {
        this.$emit('update:visible', val)
      },
      get() {
        return this.visible
      }
    },
    getLabelWidth() {
      const labelWidth = this.labelWidth
      if (/^\d+$/.test(labelWidth)) {
        return this.utils.pxToRem(labelWidth)
      } else if (/^\d+px$/.test(labelWidth)) {
        const val = labelWidth.match(/^\d+/)[0]
        return this.utils.pxToRem(val)
      }
      return labelWidth
    },
    getStyle() {
      const columnNum = this.columnNum || 1
      if (columnNum > 5) {
        rcolumnNum = 5
      }
      return {
        width: `${100 / columnNum}%`
      }
    },
    treeSelectLabel() {
      const items = this.items
      const formData = this.formData
      const result = {}
      for (let i = 0; i < items.length; i++) {
        const item = items[i]
        if (item.type !== 'treeSelect') {
          continue
        }
        if (formData[item.prop] && formData[item.prop].length) {
          const { showName = 'name' } = item
          result[item.prop] = formData[item.prop]
            .map((ele) => ele[showName])
            .join(',')
        }
      }
      return result
    },
    tableSelectLabel() {
      const items = this.items
      const formData = this.formData
      const result = {}
      for (let i = 0; i < items.length; i++) {
        const item = items[i]
        if (item.type !== 'tableSelect') {
          continue
        }
        if (
          Object.prototype.toString.call(formData[item.prop]) ===
          '[object Array]'
        ) {
          const showName = item.showName || 'name'
          result[item.prop] = formData[item.prop]
            .map((ele) => ele[showName])
            .join(',')
        } else {
          result[item.prop] = formData[item.prop]
        }
      }
      return result
    },
    organizationLabel() {
      const items = this.items
      const formData = this.formData
      let result = ''
      for (let i = 0; i < items.length; i++) {
        const item = items[i]
        if (item.type !== 'organization') {
          continue
        }
        if (
          Object.prototype.toString.call(formData[item.prop]) ===
          '[object Array]'
        ) {
          const { showName = 'name', primaryKey = 'branchcode' } = item
          result =
            formData[item.prop].map((ele) => ele[showName]).join(',') ||
            formData[item.prop].map((ele) => ele[primaryKey]).join(',')
        }
      }
      return result
    },
    userlistLabel() {
      const items = this.items
      const formData = this.formData
      const result = {}
      for (let i = 0; i < items.length; i++) {
        const item = items[i]
        if (item.type !== 'userlist') {
          continue
        }
        if (
          Object.prototype.toString.call(formData[item.prop]) ===
          '[object Array]'
        ) {
          const { showName = 'name', primaryKey = 'code' } = item
          result[item.prop] =
            formData[item.prop].map((ele) => ele[showName]).join(',') ||
            formData[item.prop].map((ele) => ele[primaryKey]).join(',')
        }
      }
      return result
    },
  },
  methods: {
    handleTableSelectClear(prop) {
      this.formData[prop] = ''
      this.$nextTick(() => {
        this.clearValidate(prop)
      })
    },
    handleComponentChange(prop, item, value) {
      this.formData[prop] = value
      this.handleChange(this.formData, { items: this.items, item }, value)
    },
    handleChange(formData, { items, item }, $event) {
      if (item.change) {
        item.change(formData, { items, item }, $event)
      }
      this.$emit('item-change', { formData, items, item })
    },
    handleInput(formData, { items, item }, $event) {
      if (item.input) {
        item.input(formData, { items, item }, $event)
      }
      this.$emit('item-input', { formData, items, item })
    },
    handlePictureCardPreview(file) {
      this.imageFileDialog.imageUrl = file.url
      this.imageFileDialog.visible = true
    },
    handlePictureCardChange(prop, file, fileList) {
      this.formData[prop] = fileList
    },
    handleOpenTreeDialog(item) {
      this.treeSelectDialog.item = item
      this.treeSelectDialog.visible = true
      this.treeSelectDialog.treeData = item.options
    },
    handleOpenTableDialog(formData, { items, item }) {
      this.tableSelectDialog.item = item
      this.tableSelectDialog.columns = item.columns
      this.tableSelectDialog.keyword = ''
      this.tableSelectDialog.pager = {
        total: 0,
        pageNum: 1,
        pageSize: 10
      }
      this.tableSelectDialog.tableData = item.options
      this.$emit(
        'table-select-open',
        formData,
        { items, item },
        this.tableSelectDialog
      )
      this.tableSelectDialog.visible = true
    },
    filterNode(value, data) {
      if (!value) return true
      return data.name.indexOf(value) !== -1
    },
    filterTree(val) {
      this.$refs.selectTree.filter(val)
    },
    handleFinishTreeSelect() {
      const { item } = this.treeSelectDialog
      const checkedNodes = this.$refs.selectTree.getCheckedNodes()
      this.handleChange(
        this.formData,
        { items: this.items, item: this.treeSelectDialog.item },
        checkedNodes
      )
      this.formData[item.prop] = checkedNodes
      this.treeSelectDialog.visible = false
    },
    handleFinishTableSelect() {
      const { item } = this.tableSelectDialog
      const selection = this.$refs.Table.selection
      this.handleChange(
        this.formData,
        { items: this.items, item: this.tableSelectDialog.item },
        selection
      )
      this.formData[item.prop] = selection
      this.tableSelectDialog.visible = false
    },
    handlePageChange() {
      this.$emit(
        'table-pager-change',
        this.formData,
        { items: this.items, item: this.tableSelectDialog.item },
        this.tableSelectDialog
      )
    },
    handleTableSearch() {
      this.tableSelectDialog.pager.pageNum = 1
      this.$emit(
        'table-search',
        this.formData,
        { items: this.items, item: this.tableSelectDialog.item },
        this.tableSelectDialog
      )
    },
    handleRowClick(row) {
      this.tableSelectControl(row)
    },
    handleTableSelect(selection, row) {
      this.tableSelectControl(row)
    },
    tableSelectControl(row) {
      row.flag = !row.flag
      if (this.tableSelectDialog.item?.singleChoice) {
        this.$refs.Table.clearSelection()
        const { primaryKey = 'id' } = this.tableSelectDialog.item
        this.tableSelectDialog.tableData.forEach((ele) => {
          if (ele[primaryKey] !== row[primaryKey]) {
            ele.flag = false
          }
        })
      }
      this.$refs.Table.toggleRowSelection(row, row.flag)
    },
    resetFields() {
      this.$refs.ruleForm && this.$refs.ruleForm.resetFields()
      if (this.$refs.customComponent) {
        for (let i = 0; i < this.$refs.customComponent.length; i++) {
          const element = this.$refs.customComponent[i]
          if (
            Object.prototype.toString.call(element.resetFields) ===
            '[object Function]'
          ) {
            element.resetFields()
          }
        }
      }
      this.formData = {}
    },
    clearValidate(props) {
      this.$refs.ruleForm && this.$refs.ruleForm.clearValidate(props)
    },
    init(initFn) {
      initFn.forEach((fn) => {
        fn()
      })
    },
    handleFinishForm() {
      this.submitting = true
      let flag = true
      if (this.$refs.customComponent) {
        for (let i = 0; i < this.$refs.customComponent.length; i++) {
          const element = this.$refs.customComponent[i]
          element.validate && element.validate((valid, object) => {
            flag = valid
          })
          if(!flag) {
            this.submitting = false
            return
          }
        }
      }
      this.$refs.ruleForm.validate((valid, object) => {
        if (valid) {
          this.$emit('submit-form', this.formData)
          if (this.autoCloseAfterSubmit) {
            this.formDialogVisible = false
          }
        } else {
          this.submitting = false
        }
      })
    },
    handleOpenOrganizationDialog(item) {
      this.branchcode = this.$store.state?.user?.branchinnercode
      if (item.defaultValue?.length) {
        this.branchcode = item.defaultValue[0].branchcode
      }
      this.organizationDialog.item = item
      this.organizationDialog.visible = true
    },
    closeOrganization(value) {
      if (value?.length) {
        const { item } = this.organizationDialog
        this.formData[item.prop] = value
      }
      this.organizationDialog.visible = false
    },
    handleOpenUserlistDialog(item) {
      this.userListDialog.item = item
      this.userListDialog.visible = true
    },
    closeUserList(value) {
      if (value?.length) {
        const { item } = this.userListDialog
        this.formData[item.prop] = value
      }
      this.userListDialog.visible = false
    },
    handleDialogOpen() {
      this.submitting = false
    }
  },
  watch: {
    defaultItems: {
      handler(newValue) {
        const formData = {}
        const initFn = []
        for (let i = 0; i < newValue.length; i++) {
          const element = newValue[i]
          formData[element.prop] = element.defaultValue
          if (this.isInit && element.change) {
            initFn.push(
              ((_formData, { items, item }, value) => {
                return () => element.change(formData, { items, item }, value)
              })(
                formData,
                { items: newValue, item: element },
                formData[element.prop]
              )
            )
          }
        }
        this.items = [...newValue]
        this.formData = formData
        this.$nextTick(() => {
          this.init(initFn)
        })
      },
      immediate: true
    }
  }
}
</script>
<style lang="scss" scoped>
.el-date-editor,
.el-select {
  width: 100%;
}
.tool-search {
  display: flex;
  .el-input {
    width: 250px;
    margin-right: 10px;
  }
}
.tool-table {
  margin-top: 15px;
  height: calc(100% - 36px - 15px);
}
.pagination {
  overflow: hidden;
  .pagination-container {
    margin-bottom: 0;
  }
}
::v-deep .select-dialog {
  .el-dialog__body {
    height: calc(69vh - 170px);
    padding-bottom: 0;
  }
}
.form-text-item {
  line-height: 36px;
}
.picture-card-disabled-content {
  display: inline-block;
  vertical-align: middle;
  margin: 0 8px 8px 0;
  text-align: center;
  overflow: hidden;
}
.picture-card-disabled-image {
  overflow: hidden;
  background-color: #fff;
  border: 1px solid #c0ccda;
  border-radius: 6px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  width: 148px;
  height: 148px;
  display: inline-block;
  position: relative;
  img {
    width: 100%;
  }
  &:hover {
    .zoom-modal {
      display: flex;
    }
  }
  .zoom-modal {
    display: none;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    display: none;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    color: #ffffff;
    background: rgba(0, 0, 0, 0.5);
    .zoom-icon {
      cursor: pointer;
    }
  }
}

.view-image {
  width: auto;
  max-width: 100%;
}
::v-deep .view-image-dialog {
  .el-dialog__body {
    text-align: center;
  }
}
</style>